#include "gpu.h"
#include <QPainter>
#include <QScreen>
#include <QGuiApplication>
#include <QImage>
#include <QVector>
#include "lineraster.h"
#include "triangleraster.h"
#include "log.h"

GPU GPU::m_instance;

void GPU::initGpu()
{
    QScreen *screen = QGuiApplication::primaryScreen();
    QRect screenGeometry = screen->geometry(); // 包括工具栏的总尺寸
    //QRect availableGeometry = screen->availableGeometry(); // 可用区域（排除工具栏）

    // 可用区域的 75%
    m_width = screenGeometry.width();
    m_height = screenGeometry.height();

    QImage image;
    if(!mp_pixmap)
    {
        mp_pixmap = new QPixmap(QSize(m_width,m_height));
        mp_pixmap->fill(Qt::white);

    }
}

void GPU::drawPoint(const Point& p)
{
    if(!mp_pixmap)
    {
        return;
    }

    QColor color(p.color.m_R, p.color.m_G, p.color.m_B, p.color.m_A);
    QPoint point(p.x, p.y);

    QPainter painter;
    painter.begin(mp_pixmap);
    painter.setPen(QPen(color, 1));
    painter.drawPoint(point);
    painter.end();
}

void GPU::drawLine(const Point &p1, const Point &p2)
{
    if(!mp_pixmap)
    {
        return;
    }

    std::vector<Point> res;
    LineRaster::rasterizeLine(res,p1, p2);

    for(auto it : res)
    {
        drawPoint(it);
    }
}

void GPU::drawTriangle(const Point &p1, const Point &p2, const Point &p3)
{
    if(!mp_pixmap)
    {
        return;
    }

    std::vector<Point> res;
    TriangleRaster::rasterTriangle(res, p1, p2, p3);

    for(auto it : res)
    {
        drawPoint(it);
    }
}

void GPU::drawUVTriangle(const Point &p1, const Point &p2, const Point &p3, const char *imageName)
{
    QImage image(imageName);

    if(!image.load(imageName))
    {
        return;
    }

    std::vector<Point> res;
    TriangleRaster::rasterTriangle(res, p1, p2, p3);


    for(auto it : res)
    {

        it.color = (m_bilinearEnable ? sampleBilinear(image,it.uv) : sampleNearest(image,it.uv));

        drawPoint(it);
    }

}

void GPU::drawImage(const char *imageName)
{
    QImage image(imageName);

    if(!image.load(imageName))
    {
        return;
    }

    int width = image.width();
    int height = image.height();

    //获取图片像素数据缓存
    if (image.format() != QImage::Format_RGB32 || image.format() != QImage::Format_ARGB32)
    {
        image = image.convertToFormat(QImage::Format_ARGB32);
    }

    uint *pixelData = reinterpret_cast<uint*>(image.bits());

    for(int i = 0;i < width; i++)
    {
        for(int j = 0;j < height; j++)
        {
            QRgb rgba = pixelData[j * width + i];
            Point p(i, j, Color(rgba));
            drawPoint(p);
        }
    }

}

void GPU::setBilinearEnable(bool enable)
{
    m_bilinearEnable = enable;
}

void GPU::setTextureWrap(TEXTURE_WRAP texture)
{
    m_wrap = texture;
}

GPU::GPU(QObject *parent) : QObject(parent)
{

}

QPixmap GPU::getPixmap()
{
    if(mp_pixmap)
    {
        return *mp_pixmap;
    }

    return QPixmap();
}

void GPU::clearPixmap()
{
    if(mp_pixmap)
    {
        mp_pixmap->scaled(QSize(m_width, m_height));
        mp_pixmap->fill(Qt::white);
    }
}

GPU::~GPU()
{
    if(mp_pixmap)
    {
        delete mp_pixmap;
        mp_pixmap = nullptr;
    }
}

Color GPU::sampleNearest(QImage &image, const vec2f &uv)
{
    vec2f myUV = uv;
    checkWrap(myUV.m_x);
    checkWrap(myUV.m_y);

    int width = image.width();
    int height = image.height();

    //获取图片像素数据缓存
    if (image.format() != QImage::Format_RGB32 || image.format() != QImage::Format_ARGB32)
    {
        image = image.convertToFormat(QImage::Format_ARGB32);
    }

     uint* pixelData = reinterpret_cast<uint*>(image.bits());

     //四舍五入到最近整数
     // u = 0 对应 x = 0，u = 1 对应 x = width - 1
     // v = 0 对应 y = 0，v = 1 对应 y = height - 1
     int x = std::round(myUV.m_x * (width - 1));
     int y = std::round(myUV.m_y * (height - 1));

     QRgb rgba = pixelData[y * width + x];

     return Color(rgba);
}

Color GPU::sampleBilinear(QImage &image, const vec2f &uv)
{
    vec2f myUV = uv;
    checkWrap(myUV.m_x);
    checkWrap(myUV.m_y);

    int width = image.width();
    int height = image.height();

    //获取图片像素数据缓存
    if (image.format() != QImage::Format_RGB32 || image.format() != QImage::Format_ARGB32)
    {
        image = image.convertToFormat(QImage::Format_ARGB32);
    }

    uint *pixelData = reinterpret_cast<uint*>(image.bits());

    float x = myUV.m_x * static_cast<float>(width - 1);
    float y = myUV.m_y * static_cast<float>(height - 1);

    //取四个像素格（floor向下取整，ceil向上取整）
    int left = std::floor(x);
    int right = std::ceil(x);
    int bottom = std::floor(y);
    int top = std::ceil(y);

    //计算上下颜色插值权重
    float yScale = 0.0F;
    if(top == bottom)
    {
        yScale = 1.0F;
    }
    else
    {
        yScale = (y- static_cast<float>(bottom)) / static_cast<float>(top - bottom);
    }

    int positionLeftTop = top * image.width() + left;
    int positionLeftBottom = bottom * image.width() + left;
    int positionRightTop = top * image.width() + right;
    int positionRightBottom = bottom * image.width() + right;



    Color leftColor = lerpRGBA(Color(pixelData[positionLeftBottom]),
                               Color(pixelData[positionLeftTop]),
                               yScale);
    Color rightColor = lerpRGBA(Color(pixelData[positionRightBottom]),
                                Color(pixelData[positionRightTop]),
                                yScale);
    float xScale = 0.0F;
    if(right == left)
    {
        xScale = 1.0F;
    }
    else
    {
        xScale = (x - static_cast<float>(left)) / static_cast<float>(right -left);
    }

    Color resultColor = lerpRGBA(leftColor, rightColor, xScale);
    return resultColor;
}

void GPU::checkWrap(float &n)
{
    if(n > 1.0F || n < 0.0F)
    {
        //取小数部分
        n = FRACTION(n);
        switch (m_wrap)
        {
        case TEXTURE_WRAP::TW_REPEAT:
        {
            n = FRACTION(n+1);
            break;
        }
        case TEXTURE_WRAP::TW_MIRROR:
        {
            n = 1.0F - FRACTION(n+1);
            break;
        }
        default:
            break;
        }
    }
}




